package net;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import core.models.Rule;

import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.transport.TransportException;
import net.schmizz.sshj.xfer.FileSystemFile;

public class SSHConnectionImpl implements SSHConnection {
	private SSHClient ssh;
	private String username;
	private char[] password;
	private String hostname;
	private int port;
	
	private Logger logger;

	public SSHClient getSsh() {
		return ssh;
	}

	public String getUsername() {
		return username;
	}

	public char[] getPassword() {
		return password;
	}

	public String getHostname() {
		return hostname;
	}

	public int getPort() {
		return port;
	}

	public SSHConnectionImpl(String username, char[] password, String hostname,
			int port) throws IOException {
		ssh = new SSHClient();
		ssh.loadKnownHosts();
		ssh.addHostKeyVerifier(new AllHostsVeryfier());
		ssh.connect(hostname, port);
		ssh.authPassword(username, password);
		logger = LoggerFactory.getLogger(SSHConnectionImpl.class);
	}

	public void disconnect() throws IOException {
		ssh.disconnect();
		ssh = null;
	}

	public boolean isConnected() {
		return ssh != null && ssh.isConnected();
	}

	@Override
	public Command execute(String command) throws IOException {
		final Session session = ssh.startSession();
		final Command cmd = session.exec(command);
		BufferedReader reader;
		String line;
		reader = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
		line = null;
		while ((line = reader.readLine()) != null) {
			logger.info(line);
		}
		reader = new BufferedReader(new InputStreamReader(cmd.getErrorStream()));
		line = null;
		while ((line = reader.readLine()) != null) {
			logger.warn(line);
		}
		return cmd;
	}

	@Override
	public File downloadInterfaces() throws IOException {
		File tempFile = File.createTempFile("RtrMngrTmp",
				Long.toString(System.currentTimeMillis()));
		tempFile.deleteOnExit();
		ssh.newSCPFileTransfer().download("/etc/network/interfaces",
				new FileSystemFile(tempFile));
		return tempFile;
	}

	@Override
	public void sendInterfaces(File file) throws IOException {
		ssh.newSCPFileTransfer().upload(new FileSystemFile(file),
				"/tmp/");
		final Command cmdMv = this
				.execute("sudo mv /tmp/"
						+ file.getName()
						+ " /etc/network/interfaces");
		final Command cmdInvoke = this.execute("sudo /etc/init.d/networking restart");
	}

	@Override
	public List<String> getRules(String table) throws IOException {
		List<String> rulesList = new ArrayList<String>();
		final Session session = ssh.startSession();
		final Command cmd = session.exec("sudo iptables -t " + table + " -S");
		BufferedReader reader = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
		String line = null;
		while ((line = reader.readLine()) != null) {
			rulesList.add(line);
		}
		session.close();
		return rulesList;
	}

	@Override
	public List<String> getInterfacesNames() throws IOException {
		List<String> interfaces = new ArrayList<String>();
		final Session session = ssh.startSession();
		final Command cmd = session.exec("cat /proc/net/dev | grep : | cut -d: -f1 | tr -d ' '");
		BufferedReader reader = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
		String line = null;
		while ((line = reader.readLine()) != null) {
			logger.info("Found interface: " + line);
			interfaces.add(line);
		}
		session.close();
		return interfaces;
	}

	@Override
	public void sendRule(Rule rule) throws IOException {
		Command cmd;
		cmd = execute("sudo " + rule.toString());
		BufferedReader reader = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
		String line = null;
		while ((line = reader.readLine()) != null) {
			logger.warn(line);
		}
	}

	@Override
	public File downloadDhcpConf() throws IOException {
		File tempFile = File.createTempFile("RtrMngrTmp",
				Long.toString(System.currentTimeMillis()));
		tempFile.deleteOnExit();
		ssh.newSCPFileTransfer().download("/etc/dhcp/dhcpd.conf", new FileSystemFile(tempFile));
		return tempFile;
	}

	@Override
	public void sendDhcpdConf(File file) throws IOException {
		ssh.newSCPFileTransfer().upload(new FileSystemFile(file),
				"/tmp/");
		final Command cmdMv = this
				.execute("sudo mv /tmp/"
						+ file.getName()
						+ " /etc/dhcp/dhcpd.conf");
		final Command cmdInvoke = this.execute("sudo /etc/init.d/isc-dhcp-server restart");		
	}

	@Override
	public long getReceivedPackets(String ifaceName) throws IOException {
		return getBytesOrPackets(ifaceName, 3);
	}

	@Override
	public long getReceivedBytes(String ifaceName) throws IOException {
		return getBytesOrPackets(ifaceName, 2);
	}

	@Override
	public long getSentPackets(String ifaceName) throws IOException {
		return getBytesOrPackets(ifaceName, 11);
	}

	@Override
	public long getSentBytes(String ifaceName) throws IOException {
		return getBytesOrPackets(ifaceName, 10);
	}
	
	private long getBytesOrPackets(String ifaceName, int printNo) throws IOException {
		String command = "cat /proc/net/dev | grep " + ifaceName + " | awk '{print $"+printNo+"}'";
		final Session session = ssh.startSession();
		final Command cmd = session.exec(command);
		BufferedReader reader = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
		String line = reader.readLine();
		long result = Long.parseLong(line);
		return result;
	}

	@Override
	public Collection<String> getIptablesLog(String filter) throws IOException {
		String command = "sudo cat /var/log/kern.log" + filter;
		final Session session = ssh.startSession();
		final Command cmd = session.exec(command);
		BufferedReader reader = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
		String line = null;
		Collection<String> lines = new ArrayList<String>();
		while ((line = reader.readLine()) != null) {
			lines.add(line);
		}
		reader = new BufferedReader(new InputStreamReader(cmd.getErrorStream()));
		while ((line = reader.readLine()) != null) {
			logger.warn(line);
		}
		return lines;
	}
}
